﻿/// <reference path="../../jquery-1.3.2-vsdoc.js" />
/// <reference path="../Shell/Base.js" />
/// <reference path="../Dashboard/Dashboard.Manager.Gadget.js" />
/// <reference path="../Gadget/Gadget.js" />
/// <reference path="../Feedback/Feedback.js"/>
(function($, epi) {
    epi = epi || {};
    epi.dashboard = epi.dashboard || {};
    epi.dashboard.manager = epi.dashboard.manager || {};
    epi.dashboard.manager.gadget = epi.dashboard.manager.gadget || {};

    /*******************************************
    ** Gadget Drag And Drop functionality  *****
    ********************************************/
    epi.dashboard.manager.gadget.move = function() {
        /// <summary>
        ///     Class providing drag and drop sorting of gadgets
        /// </summary>

        var pub = {}; // object returned by function. Exposes public methods and variables.

        pub.init = function(e) {
            /// <summary>
            ///     Event handler for epigadgetinitmove event.
            ///     Initializes jQuery UI draggable functionality on epiGadget triggering this event
            /// </summary>
            /// <param name="e" type="Event">
            ///    Event object
            /// </param>
            /// <param name="epiGadget" type="epiGadget object">
            ///    epiGadget that will be draggable.
            /// </param>
            $(e.target).draggable(_dragGadgetOptions);
        };

        var _dragNodeHelper;    // The "helper" we display when starting to drag a gadget.
        var _dropIndicator;     // DOM element indicating where the dragged gadget will be appended to DOM.
        var _fadeNode;          // Element inside the gadget we starts to move "fade-indicator".

        // Eventhandlers
        var _dragStart = function(e) {
            /// <summary>
            ///     Event handler called when dragging of a gadget starts.
            /// </summary>
            var gadget = $(this);

            gadget.addClass("epi-gadget-dragNode");
            _createFadeNode(gadget);
            _createDropIndicator(gadget);
            pub.initGadgetDropzones();

            // Init dashboard tab mouseover and mouseout events.
            $("#dashboardTabs a.epi-tabView-tab:not(div#dashboardTabs div a.epi-tabView-tab)")
                .bind("mouseover", _overTab)
                .bind("mouseout", _outTab);

            gadget.trigger("epigadgetbegindrag");
        };

        var _dragStop = function(e) {
            /// <summary>
            ///     Event handler called when dragging of a gadget ends.
            /// </summary>

            $(this).removeClass("epi-gadget-dragNode");
            _removeFadeNode();
            _dropIndicator.remove();

            // Remove droppables
            $("div.epi-gadgetContainer").droppable("destroy");
            $("div.epi-gadget:not(.epi-gadget-dragNode)").droppable("destroy")
                .removeClass("epi-gadget-coverContainer");
            $("#dashboardTabs a.epi-tabView-tab")
                .unbind("mouseover", _overTab)
                .unbind("mouseout", _outTab);
            _resetDropZonesHeight();

            $(this).trigger("epigadgetenddrag");
        };

        // Helper methods
        var _createDragNodeHelper = function() {
            /// <summary>
            ///     Creates the helper element used for dragging display
            /// </summary>
            /// <returns type="Element" />
            if (!_dragNodeHelper) {
                _dragNodeHelper = $("<div/>").addClass("epi-gadget-dragNodeHelper");
            }
            $(_dragNodeHelper).text($(this).find("h2:first").text());
            return _dragNodeHelper;
        };

        var _createFadeNode = function(gadget) {
            if (!_fadeNode) {
                _fadeNode = $("<div/>").addClass("epi-gadget-fade").css("opacity", 0.5);
            }
            gadget.prepend(_fadeNode);
        };

        var _removeFadeNode = function() {
            if (_fadeNode) {
                _fadeNode.remove();
            }
        };

        var _createDropIndicator = function(gadget) {
            /// <summary>
            ///     Creates the drop indicator element used to indicate where dragged gadget will be appended to DOM.
            /// </summary>
            /// <returns type="Element" />
            if (typeof _dropIndicator === "undefined") {
                _dropIndicator = $("<div/>").addClass("epi-gadget-dropIndicator").hide();
            }
            _dropIndicator.height(gadget.height());
        };

        pub.initGadgetDropzones = function() {
            var coverNode;
            _setDropZonesEqualHeight();
            $("div.epi-gadgetContainer").droppable(_dropZoneOptions)
                .addClass("epi-gadgetContainer-dropZone")
                .removeClass("ui-droppable");
            $("div.epi-gadget:not(.epi-gadget-dragNode):visible").droppable(_dropGadgetOptions)
                .removeClass("ui-droppable");
        };

        var _setDropZonesEqualHeight = function(gadget) {
            /// <summary>
            ///     Make sure sibling drop areas have equal height.
            /// </summary>
            var height, column, container, siblingColumn, siblingGadgetContainer;

            $("div.epi-gadgetContainer:visible").parent().each(function(i) {
                column = $(this);
                if (column.is(":first")) {
                    container = $("div.epi-gadgetContainer", column);
                    height = container.height();
                    if (height < 200) {
                        height = 200;
                        container.height(height);
                    }
                    column.siblings().each(function(i) {
                        siblingColumn = $(this);
                        siblingGadgetContainer = $("div.epi-gadgetContainer", siblingColumn);

                        if (siblingGadgetContainer.height() > height) {
                            height = siblingGadgetContainer.height();
                            siblingColumn.prevAll().children("div.epi-gadgetContainer").height(height);
                        }
                        else {
                            siblingGadgetContainer.height(height);
                        }
                    });
                }
            });
        };

        var _resetDropZonesHeight = function() {
            /// <summary>
            ///     Remove height setting from drop areas.
            /// </summary>
            $("div.epi-gadgetContainer:visible").height("auto").removeAttr("epiDropZoneHeight").removeAttr("epiDropIndicatorHeightAdded");
        };

        var _addDropIndicator = function(gadget, position) {
            var dropZone = gadget.closest("div.epi-gadgetContainer");

            switch (position) {
                case -1:
                    gadget.before(_dropIndicator);
                    break;
                case 0:
                    dropZone = gadget.append(_dropIndicator);
                    break;
                case 1:
                    gadget.after(_dropIndicator);
                    break;
            }

            _dropIndicator.show();
            _addDropZoneIndicatorHeight(dropZone);
        };

        var _addDropZoneIndicatorHeight = function(dropZone) {
            if (!dropZone.attr("epiDropIndicatorHeightAdded")) {
                var heightOfChildren = 0;
                var dropZoneHeight = dropZone.height();
                dropZone.children().each(function(i) {
                    var child = $(this);
                    heightOfChildren += child.outerHeight() + parseInt(child.css("margin-top"), 10) + parseInt(child.css("margin-bottom"), 10);
                });
                if (heightOfChildren > dropZoneHeight) {
                    var dropZoneAttributes = { epiDropZoneHeight: dropZone.height(), epiDropIndicatorHeightAdded: true };
                    dropZone.attr(dropZoneAttributes);
                    dropZone.height(heightOfChildren);
                }
            }
        };

        var _resetDropZoneWithIndicatorHeight = function(dropZone) {
            if (dropZone.attr("epiDropIndicatorHeightAdded")) {
                dropZone.height(parseInt(dropZone.attr("epiDropZoneHeight"), 10));
                dropZone.removeAttr("epiDropIndicatorHeightAdded").removeAttr("epiDropZoneHeight");
            }
        };

        var _dropTarget = function(e, ui) {
            /// <summary>
            ///     Event handler called when dragged gadget is dropped in a grid.
            /// </summary>
            if (_dropIndicator.is(":visible")) {
                _dropIndicator.replaceWith(ui.draggable);
                ui.draggable.removeClass("epi-gadget-dragNode")
                    .trigger("epigadgetmove");
            }
        };

        var _overOrOutOfGadget = function(e, ui) {
            /// <summary>
            ///     Event handler called when dragged gadget enters or leave another gadget.
            /// </summary>
            var dropNode = $(this);
            var top = dropNode.offset().top - dropNode.scrollTop();
            var bottom = dropNode.height() + top;
            var halfHeight = dropNode.height() / 2;
            var helperPosition = ui.offset.top + 10;
            // Check if we want to insert indicator before or after current gadget.
            if (helperPosition > top - 60 && helperPosition < top + halfHeight && !dropNode.prev().hasClass("epi-gadget-dragNode")) {
                _addDropIndicator(dropNode, -1);
            } else if (helperPosition < bottom + 60 && helperPosition > top + halfHeight && !dropNode.next().hasClass("epi-gadget-dragNode")) {
                _addDropIndicator(dropNode, 1);
            }
        };

        var _overDropZone = function(e, ui) {
            /// <summary>
            ///     Event handler called when dragged gadget enters a drop area.
            /// </summary>
            var dropZone = $(this);
            _dropIndicator.remove();
            if (dropZone.children(".epi-gadget-dragNode").length === 0) {
                _addDropIndicator(dropZone, 0);
            }
        };

        var _outOfDropZone = function(e, ui) {
            _dropIndicator.remove();
            _resetDropZoneWithIndicatorHeight($(e.target));
        };

        // Move gadgets between tabs
        var _tabTimer;
        var _tabShowHandler = function(e, ui) {
            pub.initGadgetDropzones();
        };

        var _overTab = function(e) {
            var tab = $(this);
            var tabView = tab.closest("ul").parent();
            tabView.epiTabView().bind("epitabshow", _tabShowHandler);
            tab.addClass("epi-tabView-tab-gadgetOver");
            _tabTimer = window.setTimeout(function() { tabView.epiTabView("select", tab); }, 1200);
        };

        var _outTab = function(e) {
            var tab = $(this);
            var tabView = tab.closest("ul").parent();
            tab.removeClass("epi-tabView-tab-gadgetOver");
            tabView.epiTabView().unbind("epitabshow", _tabShowHandler);
            if (_tabTimer) {
                window.clearTimeout(_tabTimer);
                _tabTimer = null;
            }
        };

        // Option objects for droppables.
        var _dropZoneOptions = {
            addClasses: false,
            activeClass: "epi-gadgetContainer-dropZone",
            greedy: false,
            tolerance: "pointer",
            drop: _dropTarget,
            over: _overDropZone,
            out: _outOfDropZone
        };

        var _dropGadgetOptions = {
            addClasses: false,
            greedy: false,
            tolerance: "pointer",
            over: _overOrOutOfGadget,
            out: _overOrOutOfGadget
        };

        var _dragGadgetOptions = { // draggable options
            addClasses: false,
            appendTo: ".epi-dashboardTabPanelContainer:visible",
            containment: ".epi-dashboardTabPanelContainer:visible",
            cursor: "move",
            cursorAt: { top: 10, left: 60 },
            distance: 5,
            handle: "div.epi-gadgetHeader",
            helper: _createDragNodeHelper,
            refreshPositions: true,
            revert: "invalid",
            scrollSensitivity: 80,
            start: _dragStart,
            stop: _dragStop
        };

        return pub;
    } ();

})(epiJQuery, epi);
